package judesart.app.repository;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import judesart.app.domain.Artwork;
import judesart.app.domain.Gallery;
import judesart.app.domain.Room;
import judesart.app.domain.RoomArtwork;
import judesart.app.shared.ValidationException;
import judesart.app.validation.AppValidator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class GalleryDAOImpl implements GalleryDAO
{
    private final static Log LOGGER = LogFactory.getLog(GalleryDAOImpl.class);

    @PersistenceContext
    private EntityManager entityManager;

    @Inject
    private AppValidator validator;

    @Override
    public int countGalleries(Long artistId)
    {
        return (Integer) entityManager.createNamedQuery(
                "Gallery.countByArtistId").setParameter("artistId", artistId).getSingleResult();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Gallery createGallery(Gallery gallery) throws ValidationException
    {
        validator.validate(gallery);
        entityManager.persist(gallery);
        entityManager.flush();
        return gallery;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteGallery(Long galleryId)
    {
        Gallery gallery = entityManager.find(Gallery.class, galleryId);
        entityManager.remove(gallery);
        entityManager.flush();
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public List<Gallery> findGalleries(Long artistId, int startAt,
            int maxElements)
    {
        List<Gallery> result = entityManager.createNamedQuery(
                "Gallery.findByArtistId").setParameter("artistId", artistId).setFirstResult(
                startAt).setMaxResults(maxElements).getResultList();
        loadGalleriesDependencies(result);
        return result;
    }

    private void loadGalleriesDependencies(List<Gallery> result)
    {
        for (Gallery gallery : result)
        {
            loadGalleryDependencies(gallery);
        }
    }

    private void loadGalleryDependencies(Gallery gallery)
    {
        for (Room room : gallery.getRooms())
        {
            for (RoomArtwork art : room.getArtworks())
            {

            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Long> findGalleriesIdsByArtworkId(Long artworkId)
    {
        List<Room> rooms = entityManager.createNamedQuery(
                "RoomArtwork.findRoomsByArtworkId").setParameter("artworkId",
                artworkId).getResultList();
        List<Long> result = new ArrayList<Long>();
        for (Room room : rooms)
        {
            result.add(room.getGallery().getId());
        }
        return result;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Gallery findGalleryById(Long galleryId)
    {
        Gallery gallery = entityManager.find(Gallery.class, galleryId);
        loadGalleryDependencies(gallery);
        return gallery;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Gallery updateGallery(Gallery gallery) throws ValidationException
    {
        validator.validate(gallery);
        gallery = entityManager.merge(gallery);
        entityManager.flush();
        return gallery;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Gallery addRoomToGallery(Gallery gallery, Room room)
    {
        gallery = entityManager.merge(gallery);
        room.setCreatedAt(new Date());
        room.setGallery(gallery);
        if (gallery.getRooms() == null)
        {
            gallery.setRooms(new ArrayList<Room>());
        }
        gallery.getRooms().add(room);
        entityManager.flush();
        return gallery;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Gallery deleteRoomFromGallery(Gallery gallery, String roomKey)
    {
        gallery = entityManager.merge(gallery);
        Room found = null;
        for (Room _room : gallery.getRooms())
        {
            if (_room.getKey().equals(roomKey))
            {
                found = _room;
                break;
            }
        }
        if (found != null)
        {
            gallery.getRooms().remove(found);
        }
        entityManager.flush();
        return gallery;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Room updateRoom(Room room)
    {
        LOGGER.debug(" > update room 1 [" + room.getName() + "]");
        Room _room = entityManager.merge(room);
        LOGGER.debug(" > update room 2 [" + _room.getName() + "]");
        _room.setName(room.getName());
        LOGGER.debug(" > update room 3 [" + _room.getName() + "]");
        entityManager.flush();
        return room;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Room findRoomByKey(String roomKey)
    {
        Room room = entityManager.find(Room.class, roomKey);
        loadGalleryDependencies(room.getGallery());
        return room;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Room addArtworkToRoom(Room room, Artwork artwork)
    {
        room = entityManager.merge(room);
        if (room.getArtworks() == null)
        {
            room.setArtworks(new ArrayList<RoomArtwork>());
        }
        for (RoomArtwork roomArt : room.getArtworks())
        {
            if (roomArt.getArtworkId().longValue() == artwork.getId().longValue())
            {
                return room;
            }
        }
        RoomArtwork roomArtwork = new RoomArtwork();
        roomArtwork.setArtworkId(artwork.getId());
        roomArtwork.setRoom(room);
        room.getArtworks().add(roomArtwork);
        entityManager.flush();
        return room;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Room deleteArtworkFromRoom(Room room, Artwork artwork)
    {
        room = entityManager.merge(room);
        RoomArtwork found = null;
        for (RoomArtwork roomArt : room.getArtworks())
        {
            if (roomArt.getArtworkId().longValue() == artwork.getId().longValue())
            {
                found = roomArt;
                break;
            }
        }
        if (found != null)
        {
            room.getArtworks().remove(found);
        }
        entityManager.flush();
        return room;
    }

}
